
#ifndef DESIGN_PATTERNS_ITERATOR_LIST_H_
#define DESIGN_PATTERNS_ITERATOR_LIST_H_

#include "collection.hpp"

template<typename T>
class Node
{
public:
  T data_;
  Node* next_;

  explicit Node(const T& data, Node* next = nullptr);

  Node() = default;
};

template<typename T>
  Node<T>::Node(const T& data, Node* next)
      : data_(data)
      , next_(next) { }

template<typename X>
class ListIterator;

template<typename E>
class List : public Collection<E>
{
  typedef Node<E>* NodePtr;

  friend class ListIterator<E>;

private:
  int size_;
  NodePtr dummy_;
  NodePtr tail_;

public:

  explicit List();

  void Add(const E& e) override;

  void Remove(const E& e) override;

  Iterator<E>* GetIterator() override;
};

template<typename E>
  List<E>::List()
  {
    size_ = 0;
    dummy_ = new Node<E>();
    tail_ = dummy_;
  }

template<typename E>
  void List<E>::Add(const E& e)
  {
    auto* node = new Node<E>(e);
    tail_->next_ = node;
    tail_ = node;
    ++size_;
  }

template<typename E>
  void List<E>::Remove(const E& e)
  {
    auto* pre = dummy_;
    auto* cur = dummy_->next_;
    while (cur != nullptr) {
      if (cur->data_ == e) {
        pre->next_ = cur->next_;
        delete cur;
        break;
      }
      pre = cur;
      cur = cur->next_;
    }
  }

template<typename E>
  Iterator<E>* List<E>::GetIterator()
  {
    return new ListIterator<E>(this);
  }

template<typename E>
class ListIterator : public Iterator<E>
{
private:
  Node<E>* current;
public:
  explicit ListIterator(List<E>* c);

  E& Get() override;

  void Next() override;

  bool HasMore() override;
};

template<typename E>
  ListIterator<E>::ListIterator(List<E>* c)
      : current(c->dummy_
                 ->next_) { }

template<typename E>
  E& ListIterator<E>::Get()
  {
    return current->data_;
  }

template<typename E>
  void ListIterator<E>::Next()
  {
    current = current->next_;
  }

template<typename E>
  bool ListIterator<E>::HasMore()
  {
    return current;
  }

#endif //DESIGN_PATTERNS_ITERATOR_LIST_H_
